#pragma once
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <sqlite3.h>
#include <boost/algorithm/string.hpp>
#include <random>
#include <iomanip>
#include <atomic>
#include <sys/stat.h>
#include "Log.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cerrno>
using namespace std;

// 字符串分割类
class StringHelper {
public :
    static void splitString(const std::string& str, std::vector<std::string>* tokens, const std::string& sep) {
        boost::split((*tokens), str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
    }
};


// sqlite数据库工作类
class SqliteHelper {
public :
    typedef int (*SqliteCallback)(void*, int, char**, char**); // 执行语句的回调函数
    SqliteHelper(const string& dbfile) 
        :_dbfile(dbfile)
        ,_handler(nullptr)
    {}

    bool open(int safe_level = SQLITE_OPEN_FULLMUTEX) {
        // int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs );
        int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);
        if (ret == SQLITE_OK) {
            LOG(Info) << "打开/创建数据库成功" << endl;
            return true;
        }
        LOG(Error) << "创建/打开sqlite数据库失败: " << sqlite3_errmsg(_handler) << endl;
        return false;

    }
    bool execute(const string& sql, SqliteCallback callback, void* arg) {
        //int sqlite3_exec(sqlite3*, char *sql, int (*callback) (void*,int,char**,char**), void* arg, char **err) 
        int ret = sqlite3_exec(_handler, sql.c_str(), callback, arg, nullptr);
        if (ret != SQLITE_OK) {
            LOG(Debug) << "执行语句 [" << sql << "] 失败: " << sqlite3_errmsg(_handler) << endl;
            return false;
        }
        return true;
    }

    void close() {
        if (_handler) {
            sqlite3_close_v2(_handler);
        }
    }

private :
    string _dbfile;
    sqlite3* _handler; // sqlite数据库的操作句柄 
};

// 生成唯一的uuid工具类
class UuidHelper {
public :
    static string uuid() {
        random_device rd;
        mt19937_64 gernator(rd());
        uniform_int_distribution<int> distribution(0, 255); // 生成0到255之间的随机数
        stringstream ss;
        for (int i = 0; i < 8; i++) {
            ss << setw(2) << setfill('0') << hex << distribution(gernator);
            if (i == 3 || i == 5 || i == 7) {
                ss << "-";
            }
        }
        static atomic<size_t> seq(1);
        size_t num = seq.fetch_add(1);
        for (int i = 7; i >= 0; i--) {
            ss << setw(2) << setfill('0') << hex << ((num >> (i * 8)) & 0xff);
            if (i == 6) {
                ss << "-";
            }
        }
        return ss.str();
    }

};


// 文件操作类
class FileHelper {
public :
    // 判断一个文件是否存在
    static bool exists(const string& filename) {
        struct stat st;
        return stat(filename.c_str(), &st) == 0;
    }
    // 获取文件的大小
    static size_t size(const string& filename) {
        // 获取文件状态
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret != 0) {
            LOG(Error) << "文件: " << filename << "不存在!" << endl;
            return 0;
        }
        return st.st_size;
    }
    // 指定位置读取指定大小的文件内容
    static bool read(const string& filename, char* body, size_t offset, size_t len) {
        // 先打开文件
        ifstream in(filename, ios::binary | ios::in);
        if (!in.is_open()) {
            LOG(Error) << "打开文件: " << filename << "失败!" << endl;
            return false;
        }
        // 修改文件读取位置
        in.seekg(offset, ios::beg);
        // 读取
        in.read(body, len);
        if (in.good() == false) {
            LOG(Error) << "读取文件: " << filename << "出错!" << endl;
            in.close();
            return false;
        }
        in.close();
        return true;
    }
    // 读物文件全部内容
    static bool read(const string& filename, string& body) {
        // 先获取文件大小
        body.clear();
        size_t len = size(filename);
        body.resize(len);
        return read(filename, &body[0], 0, len);
    }

    // 指定位置写入指定大小的内容
    static bool write(const string& filename, char* body, size_t offset, size_t len) {
        // 先打开文件`
        fstream out(filename, ios::binary | ios::in | ios::out);
        if (!out.is_open()) {
            LOG(Error) << "打开文件: " << filename << "失败!" << endl;
            return false;
        }
        // 改变文件的写入位置
        out.seekp(offset, ios::beg);
        out.write(body, len);
        if (out.good() == false) {
            LOG(Error) << "写入文件: " << filename << "出错!" << endl;
            out.close();
            return false;
        }
        out.close();
        return true;
    }
    // 在起始位置写文件
    static bool write(const string& filename, char* body, size_t len) {
        return write(filename, body, 0, len);
    }

    static bool createFile(const string& filename) {
        if (exists(filename)) {
            return true;
        }
        // 打开文件即可
        fstream fs(filename, ios::out | ios::binary);
        if (!fs.is_open()) {
            LOG(Error) << "创建文件: " << filename << "失败! strerror: " << strerror(errno) << endl;
            return false;
        }
        fs.close();
        return true;
    }
    // 删除文件
    static bool removeFile(const string& filename) {
        int ret = remove(filename.c_str());
        if (ret != 0) {
            LOG(Waring) << "删除文件: " << filename << "失败!" << endl;
            return false;
        }
        //LOG(Debug) << "删除文件: " << filename << " 成功!" << endl;
        return true;
    }

    // 创建目录
    static bool createDirectory(const string& pathname) {
        if (exists(pathname)) {
            return true;
        }
        string commd = "mkdir -p " + pathname;
        int ret = system(commd.c_str());
        if (ret != 0 && errno != EEXIST) {
            LOG(Waring) << "创建目录: " << pathname << "失败!" << endl;
            return false;
        }
        return true;
    }
    // 删除目录
    static bool removeDirectory(const string& pathname) {
        string commd = "rm -rf " + pathname;
        int ret =  system(commd.c_str());
        if (ret == -1) {
            LOG(Waring) << "删除目录: " << pathname << "失败!" << endl;
            return false;
        }
        return true;
    }

    // 获取一个文件的父目录
    static string parentDiretoty(const string& filename) {
        if (filename.empty()) {
            LOG(Debug) << "文件名为空!" << endl;
            return "";
        }
        // if (!exists(filename)) {
        //     LOG(Debug) << "获取文件: " << filename << "失败, 文件不存在!" << endl;
        //     return "";
        // }
        auto pos = filename.rfind("/");
        if (pos == string::npos) {
            return "./";
        }
        return filename.substr(0, pos);
    }

    // 重命名一个文件
    static bool rename(const string& filename, const string& newfilename) {
        if (filename.empty()) {
            LOG(Debug) << "原文件名为空!" << endl;
            return false;
        }
        if (newfilename.empty()) {
            LOG(Debug) << "新文件名为空!" << endl;
            return false;
        }
        if (!exists(filename)) {
            LOG(Debug) << "重命名文件: " << filename << "失败, 原文件不存在!" << endl;
            return false;
        }
        return ::rename(filename.c_str(), newfilename.c_str()) == 0;
    }

};